package Java8新特性.StreamAPI;

import org.junit.Test;
import 示例类.Employee;
import 示例类.EmployeeData;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @Description StreamAPI
 * Stream到底是什么呢？
 * 是数据渠道，用于操作数据源（集合、数组等）所生成的元素序列。 “集合讲的是数据，Stream讲的是计算！”
 * ！注意：
 * ①	Stream 自己不会存储元素。
 * <p>
 * ②	Stream 不会改变源对象。相反，他们会返回一个持有结果的新Stream。
 * <p>
 * ③	Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
 * @Author 俊昭
 * @Date 2022/5/12
 */
public class StreamTest {
    /**
     * 针对的是对数据的运算 与 CPU交互
     */
    @Test
    public void test00() {
        // 1- 创建 Stream
        // 一个数据源（如：集合、数组），获取一个流
        // 方式一 通过集合
        List<Employee> employees = EmployeeData.getEmployees();
        // default Stream<E> stream() 返回一个顺序流
        Stream<Employee> s11 = employees.stream();// 顺序流
        // default Stream<E> parallelStream() 返回一个并行流
        Stream<Employee> s12 = employees.parallelStream();// 并行流

        // 方式二 通过数组
        // static <T> Stream<T> stream(T[] array,
        int[] ints = {1, 2, 3, 4, 5};
        IntStream s21 = Arrays.stream(ints);

        Stream<Object> s22 = Arrays.stream(employees.toArray());

        Employee e1 = new Employee(1);
        Employee e2 = new Employee(2);
        Employee[] employees1 = {e1, e2};
        Stream<Employee> s23 = Arrays.stream(employees1);

        // 方式三 Stream的 of()
        Stream<Integer> s3 = Stream.of(1, 2, 3, 4, 5);

        // 方式四 创建无限流
        // 迭代
        // public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        Stream<Integer> s41 = Stream.iterate(0, t -> t + 2);
        // 生成
        // public static<T> Stream<T> generate(Supplier<T> s)

        Stream<Double> s42 = Stream.generate(Math::random);


        // 2- 中间操作
        // void forEach(Consumer<? super T> action)  对流中的每个元素执行一个操作。
        // 一个中间操作链，对数据源的数据进行处理
        // 多个中间操作可以连接起来形成一个流水线，除非流水线上触发终止操作，否则中间操作不会执行任何的处理！
        // 而在终止操作时一次性全部处理，称为“惰性求值”。
        // ①-筛选与切片
        // filter(Predicate p) 接收 Lambda ， 从流中排除某些元素

        employees.stream().filter(employee -> employee.getAge() >= 30).forEach(System.out::println);
        System.out.println();

        // distinct() 筛选，通过流所生成元素的 hashCode() 和 equals() 去除重复元素

        //limit(long maxSize) 截断流，使其元素不超过给定数量
        employees.stream().limit(4).forEach(System.out::println);
        System.out.println();

        // skip(long n) 跳过元素，返回一个扔掉了前 n 个元素的流。若中不足 n 个，则返回一 个空流。与 limit(n) 互补
        employees.stream().skip(4).forEach(System.out::println);
        System.out.println();
        // ②-映射
        //map(Function f )接收一个函数作为参数，
        // 该函数会被应用到每个元 素上，并将其映射成一个新的元素。
        //mapToDouble(ToDoubleFunction f)接收一个函数作为参数，
        // 该函数会被应用到每个元素上，产生一个新的 DoubleStream 。
        //mapToInt(ToIntFunction f)接收一个函数作为参数
        // ，该函数会被应用到每个元素上，产生一个新的 IntStream 。
        //mapToLong(ToLongFunction f)接收一个函数作为参数，
        // 该函数会被应用到每个元素上，产生一个新的 LongStream 。
        //flatMap(Function f)接收一个函数作为参数，
        // 将流中的每个值都换成另一个流，然后把所有流连接成一个流

        // ③-排序
        //sorted()产生一个新流，其中按自然顺序排序
        //sorted(Comparator com) 产生一个新流，其中按比较器顺序排序


        // 3- 终止操作(终端操作)
        // 一旦执行终止操作，就执行中间操作链，并产生结果。之后，不会再被使用
        // ①-匹配与查找
        // allMatch(Predicate p )检查是否匹配所有元素
        //anyMatch (Predicate p)检查是否至少匹配一个元素
        //noneMatch(Predicate p) 检查是否没有匹配所有元素
        //findFirst()返回第一个元素
        //findAny()返回当前流中的任意元素
        //count() 返回流中元素总数
        //max(Comparator c) 返回流中最大值
        //min(Comparator c)返回流中最小值
        // void forEach(Consumer<? super T> action)  对流中的每个元素执行一个操作。
        // 使用 Collection 接口需要用户去做迭代，称为 外部迭代 。相反， Stream API 使用内部迭代 它帮你把迭代做了

        // ②-归约
        //reduce(T iden, BinaryOperator b)可以将流中元素反复结合起来，得到一个值。返回 T
        //reduce(BinaryOperator b)可以将流中元素反复结合起来，得到一个值。返回 Optional<T>

        // ③-收集
        // collect(Collector c) 将流转换为其他形式。接收一个Collector接口的实现，用于给 Stream 中元素做汇总的方法
        // 另外，Collectors 实用类提供了很多静态方法，可以方便地创建常见收集器实例，
    }
}
